package com.lucan.tracking.plugin.visitor.method

import com.lucan.tracking.annotations.Track
import com.lucan.tracking.enums.Sequence
import com.lucan.tracking.plugin.visitor.anno.ConfigurationAnnoVisitor
import com.lucan.tracking.plugin.visitor.anno.TrackAnnoVisitor
import org.objectweb.asm.AnnotationVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import org.objectweb.asm.commons.AdviceAdapter

/**
 * @author qihailong
 * @date 2018/7/23 上午11:39
 * @description TODO
 */

class TrackMethodVisitor extends AdviceAdapter {

    private String mMethodName
    private String mAction
    private String mSequence
    private String mBeanId
    private boolean mPost

    TrackMethodVisitor(int api, MethodVisitor mv, int access, String name, String desc) {
        super(api, mv, access, name, desc)
        mMethodName = name
    }

    @Override
    AnnotationVisitor visitAnnotation(String desc, boolean visible) {
        AnnotationVisitor annotationVisitor = super.visitAnnotation(desc, visible)
        if (Type.getDescriptor(Track.class) == desc) {
            return new TrackAnnoVisitor(api, annotationVisitor, desc, { Map<String, String> map ->
                mSequence = map?.get(TrackAnnoVisitor.KEY_SEQUENCE, "AFTER") ?: "AFTER"
                mBeanId = map?.get(TrackAnnoVisitor.KEY_BEAN_ID, "") ?: ""
                mAction = map?.get(TrackAnnoVisitor.KEY_ACTION, "NOW") ?: "NOW"
                mPost = Boolean.valueOf(map?.get(TrackAnnoVisitor.KEY_POST, "true") ?: "true")
            })
        }
        return annotationVisitor
    }

    @Override
    protected void onMethodEnter() {
        super.onMethodEnter()
        if (mSequence != Sequence.BEFORE.toString()) {
            return
        }
        insert()
    }

    @Override
    protected void onMethodExit(int opcode) {
        super.onMethodExit(opcode)
        if (mSequence != Sequence.AFTER.toString()) {
            return
        }
        insert()
    }

    /**
     * 插入打点代码
     */
    private void insert() {
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/lucan/tracking/TKMonitor",
                "getInstance", "()Lcom/lucan/tracking/TKMonitor;", false)
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/lucan/tracking/apt/Beans",
                "get${mBeanId}Url", "()Ljava/lang/String;", false)
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/lucan/tracking/apt/Beans",
                "get${mBeanId}Params", "()Ljava/util/Map;", false)
        if (mPost) {
            mv.visitInsn(Opcodes.ICONST_1)//true
        } else {
            mv.visitInsn(Opcodes.ICONST_0)//false
        }
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "com/lucan/tracking/TKMonitor",
                "sendTrack${mAction.substring(0, 1).toUpperCase()}" + "${mAction.substring(1).toLowerCase()}",
                "(Ljava/lang/String;Ljava/util/Map;Z)V", false)
    }

}
